﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Net.Sockets;
using System.Threading;
using System.Net;
using GMapNET;
using System.IO;
using System.Drawing.Imaging;


namespace UGSV_GUI
{
    public partial class cp : Form
    {
        Socket udpThing;
        IPEndPoint theEP;

        ////bool continueBeating;
        State currentState = null;
        Server theWebServer = null;
        DateTime lastCommunication = DateTime.Now;
        Image imageToShow = Image.FromFile("test.jpg");


        public cp()
        {
            //DO NOT REMOVE
            InitializeComponent();

            currentState = new State();
            theWebServer = new Server(currentState);
            theWebServer.startServer();

            startUDPListener();
            button3.Select();
            pictureBox1.Image = imageToShow;
        }

        public void startUDPListener()
        {
            theEP = new IPEndPoint(IPAddress.Any,441);

            udpThing = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);  //for random position data

            udpThing.Bind(theEP);

            updateStatus.RunWorkerAsync();
            videoUpdate.RunWorkerAsync();
        }

        /// <summary>


        /// <summary>
        /// Receive data from buffer
        /// </summary>
        /// <returns></returns>
        public string receiveData()
        {
            //data
            if (udpThing == null)
                return "NODATA"; //error if this happens, need to correct. dont know what to do about it yet though
            try
            {
                if (udpThing.Available > 0)
                {
                    byte[] incomingBuffer = new byte[100];
                    udpThing.Receive(incomingBuffer);

                    lastCommunication = DateTime.Now;
                    return ASCIIEncoding.UTF8.GetString(incomingBuffer);
                }
                else
                    return "NODATA";
            }
            catch (Exception sda)
            {
                Console.WriteLine("ERROR RECEIVING" + sda.ToString());
                return "NODATA";
            }

        }

        ///// <summary>
        ///// Receives an image
        ///// </summary>
        ///// <returns></returns>
        //public Image receiveImage()
        //{
        //    //data
        //    if (imageThing == null)
        //        return null;
        //    try
        //    {
        //        if (udpThing.Available >= 41000)
        //        {
        //            byte[] incomingBuffer = new byte[udpThing.Available];
        //            imageThing.Receive(incomingBuffer);

        //            lastCommunication = DateTime.Now;
        //            Console.WriteLine("Received Image");
        //            return Image.FromStream(new MemoryStream(incomingBuffer));
        //        }
        //        else
        //            return null;
        //    }
        //    catch (Exception sda)
        //    {
        //        Console.WriteLine("ERROR RECEIVING" + sda.ToString());
        //        return null;
        //    }
        //}

        public void updateStatus_DoWork(object sender, DoWorkEventArgs e)
        {
            string[] parts = new string[2];
            string receivedString;

            while (!e.Cancel)
            {
                try
                {
                    receivedString = " ";
                    receivedString = receiveData();
                    if (receivedString.StartsWith("BEACON"))
                    {
                        Console.WriteLine(receivedString + "\n");
                        //Console.WriteLine("Received Beacon: " + receivedString);
                        parts = receivedString.Split(' ');
                        updateStatus.ReportProgress(0, (object)parts);
                    }
                }
                catch (Exception asdsa)
                {
                    Console.WriteLine("Problem updating beacon" + asdsa.ToString());
                }

                if (this.updateStatus.CancellationPending)
                {
                    e.Cancel = true;
                    break;
                }
                Thread.Sleep(200);
            }

        }

        private void updateStatus_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            int passedNum = e.ProgressPercentage;
            string[] parts = (string[])e.UserState;
            if (parts.Length >= 4)
            {
                lblLastUpdate.Text = DateTime.Now.ToString();
                lblCoordinates.Text = parts[1];  
                lblOrientation.Text = parts[2];
                lblStatus.Text = "F: " + parts[3] + " R: " + parts[4];
                try
                {
                    String[] coords = parts[0].Split(',');
                    double lat = Double.Parse(coords[0]);
                    double longitude = Double.Parse(coords[2]);
                    if((longitude != 0)&&(lat != 0))
                        gMapControl1.CurrentPosition = new PointLatLng(lat, longitude);     //center map on coordinates
                }
                catch
                {
                    //
                }
            }
        }

        private void button4_Click(object sender, EventArgs e)
        {
            currentState.goForward();
        }

        private void button7_Click(object sender, EventArgs e)
        {
            currentState.turnStraight();
        }

        private void button6_Click(object sender, EventArgs e)
        {
            currentState.turnRight();
        }

        private void button8_Click(object sender, EventArgs e)
        {
            currentState.turnLeft();
        }

        private void button3_Click(object sender, EventArgs e)
        {
            currentState.stop();
        }

        private void button5_Click(object sender, EventArgs e)
        {
            currentState.goBackward();
        }

        private void cp_Load(object sender, EventArgs e)
        {

        }

        private void cp_FormClosing(object sender, FormClosingEventArgs e)
        {
            //udpThing.Close();
            updateStatus.CancelAsync();
            theWebServer.stopServer();
        }

        private void trackBar1_Scroll(object sender, EventArgs e)
        {
            currentState.setSpeed(trackBar1.Value);
        }

        private void gMapControl1_Load(object sender, EventArgs e)
        {

        }

        private void gMapControl1_Load_1(object sender, EventArgs e)
        {
            gMapControl1.RenderMode = RenderMode.GDI_PLUS;
            gMapControl1.SetCache("VirtualEarthMap");
            gMapControl1.MapType = GMapType.VirtualEarthMap;
            gMapControl1.Zoom = 5;
            //gMapControl1.OnMakerPositionUpdated += new GMapControl.MarkerPositionUpdated(gMapControl1_OnMakerPositionUpdated);
            ultraTrackBar1.Value = 5;
            ultraTrackBar1.SetRange(0, 20);
            gMapControl1.CurrentMarkerEnabled = false;
            //gMapControl1.OnPaintComplete += new GMapControl.PaintComplete(gMapControl1_OnPaintComplete);
            gMapControl1.Language = "en";
            gMapControl1.MouseWheel += new MouseEventHandler(gMapControl1_MouseWheel);
            gMapControl1.DoubleClick += new EventHandler(gMapControl1_DoubleClick);
            //gMapControl1.OnTileLoadStart += new GMapControl.TileLoadStart(gMapControl1_OnTileLoadStart);
            gMapControl1.CurrentPosition = new PointLatLng(30.279705, -97.738556);
            gMapControl1.UseTileCache = true;
            //gMapControl1.OnMarkerClick += new GMapControl.MarkerClick(gMapControl1_OnMarkerClick);
            //gMapControl1.OnTileLoadComplete += new GMapControl.TileLoadComplete(gMapControl1_OnTileLoadComplete);
            gMapControl1.ReloadMap();
        }



        //gmap stuff

        void gMapControl1_MouseWheel(object sender, MouseEventArgs e)
        {
            //throw new NotImplementedException();
            try
            {
                if (e.Delta < 0)
                {
                    if (ultraTrackBar1.Value > 1)
                    {
                        ultraTrackBar1.Value--;
                    }
                }
                else
                {
                    if (ultraTrackBar1.Value < 17)
                    {
                        ultraTrackBar1.Value++;
                    }
                }
            }
            catch { }
        }

        void gMapControl1_DoubleClick(object sender, EventArgs e)
        {
            PointLatLng ll = gMapControl1.FromLocalToLatLng(gMapControl1.PointToClient(Cursor.Position));
            gMapControl1.CurrentPosition = ll;
            try
            {
                if (ultraTrackBar1.Value < 17)
                {
                    ultraTrackBar1.Value++;
                }
            }
            catch { }
            gMapControl1.GoToCurrentPosition();
        }

        private void ultraTrackBar1_ValueChanged(object sender, EventArgs e)
        {
            bool freeZoomMode = true;
            //fixed annoying bug here where after a zoom, map would center on original point
            PointLatLng ll = gMapControl1.FromLocalToLatLng(gMapControl1.PointToClient(Cursor.Position));

            gMapControl1.Zoom = ultraTrackBar1.Value;
            if (freeZoomMode)
            {
                gMapControl1.CurrentPosition = ll;
                gMapControl1.GoToCurrentPosition();
            }
            gMapControl1.ReloadMap();
        }

        private void videoUpdate_DoWork(object sender, DoWorkEventArgs e)
        {
            Image currentFrame;

            while (true)
            {
                currentFrame = downloadImage();
                if (currentFrame != null)
                {
                    videoUpdate.ReportProgress(0, (object)currentFrame);
                }
            }


        }

        private void videoUpdate_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            Image theFrame = (Image)e.UserState;
            pictureBox1.Image = theFrame;

        }

        public Image downloadImage()
        {
            try
            {
                WebRequest req = WebRequest.Create("http://mattpapageorge.dlinkddns.com:8080/shot.jpg");
                WebResponse response = req.GetResponse();
                Stream stream = response.GetResponseStream();
                Image img = Image.FromStream(stream);
                stream.Close();
                return img;
            }
            catch (Exception)
            {
                //MessageBox.Show("There was a problem downloading the file");
                Thread.Sleep(5000);
            }
            return null;
        }

        private void captureVideo_Click(object sender, EventArgs e)
        {
            Image toSave = downloadImage();

            try
            {
                MemoryStream ms = new MemoryStream();
                toSave.Save(ms, ImageFormat.Jpeg);

                using (Stream file = File.OpenWrite("Image_Capture" + DateTime.Now.ToString() + ".jpg"))
                {
                    CopyStream(ms, file);
                    ms.Close();
                    file.Close();
                }
                
            }
            catch(Exception asd)
            {
                MessageBox.Show("There was a problem downloading the file");
                Console.WriteLine("There was a problem downloading the file, Exception " + asd);
            }

        }

        /// <summary>
        /// Copies the contents of input to output. Doesn't close either stream.
        /// </summary>
        public static void CopyStream(Stream input, Stream output)
        {
            byte[] buffer = new byte[8 * 1024];
            int len;
            while ((len = input.Read(buffer, 0, buffer.Length)) > 0)
            {
                output.Write(buffer, 0, len);
            }
        }

    }

}
